﻿using System;
using System.IO;
using System.Collections.Generic;
using AzukiMap.Tools.Logger;
using Geotools.Geometries;
using Geotools.IO;
using System.Collections;

namespace AzukiMap.Request
{
    public class PostGisRasterIndexParser : PostGisVectorParser
    {
        RasterIndexRecord[] _records;

        public PostGisRasterIndexParser(BinaryReader geomReader)
           : base(geomReader)
        {
            Logger.Debug(
                "PostGisRasterIndexParser.PostGisRasterIndexParser(): "
                + " geomReader.BaseStreamLength: " + geomReader.BaseStream.Length
                );
        }
        /// <summary>
        /// The respose header is only a number. 
        /// If the number is positive value　or zero, it means number of records. 
        /// If it has minus value, it is a error code. 
        /// </summary>
        protected override void ParseHeader()
        {
            if (_geomReader.BaseStream.Position != 0)
            {
                Logger.Error("PostGisDataParser: Reader position is not head.");
                throw new Exception("Reader position is not head.");
            }
            int header = _geomReader.ReadInt32();
            // has data
            if (header >= 0)
            {
                _numOfObjects = header;
                _errorCode = 0;
                _records = new RasterIndexRecord[_numOfObjects];

                Logger.Debug(
                    "PostGisDataParser.ParseHeader(): "
                    + " header = " + header.ToString()
                    );

            }
            // has error
            else
            {
                _numOfObjects = 0;
                _errorCode = header;
                _records = new RasterIndexRecord[] { };

                Logger.Debug(
                    "PostGisDataParser.ParseHeader(): No Records."
                    + " header = " + header.ToString()
                    );
            }
        }


        RasterIndexRecord GetNextRecord()
        {
            if (hasNext())
            {
                RasterIndexRecord record = new RasterIndexRecord();
                record.RasterIndex = GetRasterIndex();
                record.Extent = (GTPolygon)GetGeometryFromBinReader();

                _currentReadingRecord++;
                return record;
            }
            else
            {
                Logger.Warn("PostGisDataParser: There is no record to read in the stream.");
                throw new NoNextRecordException("There is no record to read in the stream.");
            }
        }

        protected override void ParseRecords()
        {
            if (_errorCode == 0)
            {
                while (hasNext())
                {
                    _records[_currentReadingRecord] =
                        GetNextRecord();
                }
            }
        }

        string GetRasterIndex()
        {
            return _geomReader.ReadString();
        }

        #region IEnumerable Members

        protected IEnumerator GetEnumerator()
        {
            return new RasterIndexEnum(_records);
        }

        #endregion
    }

    public class RasterIndexEnum : IEnumerator
    {
        RasterIndexRecord[] _records;
        int _pos = -1;
        bool _disposed = false;
       
        public RasterIndexEnum(RasterIndexRecord[] records)
        {
            _records = records;
        }

        #region IEnumerator Members

        public object Current
        {
            get
            {
                try
                {
                    return _records[_pos];
                }
                catch (IndexOutOfRangeException ex)
                {
                    Logger.Error("PostGisRasterIndexEnum: IndexOutOfRangeException.", ex);
                    throw new InvalidOperationException();
                }
            }
        }

        public bool MoveNext()
        {
            _pos++;
            return (_pos < _records.Length);
        }

        public void Reset()
        {
            _pos = -1;
        }

        #endregion
    }

    public struct RasterIndexRecord
    {
        public int id;
        public string RasterIndex;
        public GTPolygon Extent;
    }
}
